package cn.liangxxhu.rocketmq.core;


import cn.liangxxhu.rocketmq.core.param.MessageWrapper;
import cn.liangxxhu.rocketmq.core.strategy.MessageSendStrategyFactory;
import cn.liangxxhu.rocketmq.toolkit.TraceIdUtil;
import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.springframework.messaging.Message;

/**
 * 发送消息抽象类，统一封装消息包装、目的地构建与策略分发。
 *
 * @param <T> 业务消息体类型
 */
@Slf4j
@RequiredArgsConstructor
public abstract class AbstractCommonSendProduceTemplate<T> {

    private final MessageSendStrategyFactory strategyFactory;

    /**
     * 构建消息包装器，设置事件名、topic、tag、keys、超时、延迟等元信息。
     *
     * @param messageSendEvent 业务事件实体
     * @return 包含元信息与业务体的包装器
     */
    protected abstract MessageWrapper<T> buildBaseSendExtendParam(T messageSendEvent);

    /**
     * 基于包装器构建 Spring Messaging Message 对象（填充 header，如 keys、tags）。
     *
     * @param messageWrapper 扩充属性实体
     * @return Spring Message 对象
     */
    protected abstract Message<?> buildMessage(MessageWrapper<T> messageWrapper);

    /**
     * 构建 RocketMQ 目的地字符串：topic[:tag]
     *
     * @param messageWrapper 扩充属性实体
     * @return 目的地字符串
     */
    private String buildDestination(MessageWrapper<T> messageWrapper) {
        StringBuilder destinationBuilder = new StringBuilder(messageWrapper.getTopic());
        if (StringUtils.isNotBlank(messageWrapper.getTag())) {
            destinationBuilder.append(":").append(messageWrapper.getTag());
        }
        return destinationBuilder.toString();
    }

    /**
     * 发送消息。
     *
     * @param messageSendEvent 业务事件实体
     * @param messageType 消息类型（由策略工厂解析，如普通/延迟）
     * @return 发送结果
     */
    public SendResult send(T messageSendEvent, String messageType) {
        MessageWrapper<T> messageWrapper = buildBaseSendExtendParam(messageSendEvent);
        SendResult sendResult;
        // 处理链路追踪
        String traceId = StringUtils.defaultIfBlank(messageWrapper.getKeys(), TraceIdUtil.generateTraceId());
        TraceIdUtil.putTraceId(traceId);
        try {
            // 通过策略工厂获取对应策略并发送消息
            sendResult = strategyFactory.getMessageSendStrategy(messageType).send(buildDestination(messageWrapper),
                    buildMessage(messageWrapper), messageWrapper.getSentTimeout(), messageWrapper.getDelayTime());
            log.info("[{}] 消息发送结果：{}，消息ID：{}，消息Keys：{}", messageWrapper.getEventName(), sendResult.getSendStatus(), sendResult.getMsgId(), messageWrapper.getKeys());
        } catch (Throwable ex) {
            log.error("[{}] 消息发送失败，消息体：{}", messageWrapper.getEventName(), JSON.toJSONString(messageSendEvent), ex);
            throw ex;
        } finally {
            TraceIdUtil.clear();
        }
        return sendResult;
    }
}
